//#define AUTO_SCAN
//#define ResizeOrginTexture

using System.IO;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace BToolkit
{
#if AUTO_SCAN
    public class TextureCompress : AssetPostprocessor
#else
    public class TextureCompress
#endif
    {
        //支持填写目录或文件名
        string[] IgnoreList =
        {
            "AppIcons",
            "Get-it-for-free_08",
            "logo_small"
        };

        //图片导入时自动压缩
#if AUTO_SCAN
        void OnPreprocessTexture()
        {
            TextureImporter importer = (TextureImporter)assetImporter;
            for (int i = 0; i < IgnoreList.Length; i++)
            {
                if (importer.assetPath.Contains(IgnoreList[i])) return;
            }
            Compress(importer, EditorUserBuildSettings.activeBuildTarget);
        }
#endif

        [MenuItem("Assets/贴图压缩")]
        private static void CompressAndroid()
        {
            StartCompress(EditorUserBuildSettings.activeBuildTarget);
        }

        [MenuItem("Assets/删除所有 Normal Texture")]
        private static void DeleteMormalTexture()
        {
            StartDeleteMormalTexture(EditorUserBuildSettings.activeBuildTarget);
        }

        private static void StartCompress(BuildTarget platform)
        {
            Object[] objs = Selection.GetFiltered(typeof(Texture2D), SelectionMode.DeepAssets);
            if (objs.Length == 0)
            {
                EditorUtility.DisplayDialog("提示", "请选择贴图", "确定");
                return;
            }
            for (int i = 0; i < objs.Length; i++)
            {
                Compress(objs[i] as Texture2D, platform);
            }
        }

        private static void StartUnCompress()
        {
            Object[] objs = Selection.GetFiltered(typeof(Texture2D), SelectionMode.DeepAssets);
            if (objs.Length == 0)
            {
                EditorUtility.DisplayDialog("提示", "请选择贴图", "确定");
                return;
            }
            for (int i = 0; i < objs.Length; i++)
            {
                UnCompress(objs[i] as Texture2D);
            }
        }

        private static void Compress(Object texture, BuildTarget platform)
        {
            string path = AssetDatabase.GetAssetPath(texture);
            if (string.IsNullOrEmpty(path))
            {
                EditorUtility.DisplayDialog("提示", "传入的 texture 必须是 Project 窗口下的资源", "确定");
                return;
            }
            TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
            Compress(importer, platform);
            AssetDatabase.ImportAsset(path);
        }

        private static void Compress(TextureImporter importer, BuildTarget platform)
        {
            importer.npotScale = TextureImporterNPOTScale.None;
            if (platform == BuildTarget.StandaloneWindows64 || platform == BuildTarget.Android)
            {
                TextureImporterPlatformSettings settings = importer.GetPlatformTextureSettings("Android");
                settings.maxTextureSize = 1024;
#if ResizeOrginTexture
                if (!IsMultiOfFour(importer) || GetSize(importer) > settings.maxTextureSize)
#else
                if (!IsMultiOfFour(importer))
#endif
                {
                    ScaleToMO4(importer, settings.maxTextureSize);
                }
                settings.overridden = true;
                settings.allowsAlphaSplitting = false;
                //这里不考虑ETC_RGBA4Crunched的情况，因为某些非透明图即使是4的倍数也无法使用ETC_RGBA4Crunched
                settings.format = TextureImporterFormat.ETC2_RGBA8Crunched;
                settings.compressionQuality = 100;
                importer.SetPlatformTextureSettings(settings);
            }
            else if (platform == BuildTarget.iOS)
            {
                TextureImporterPlatformSettings settings = importer.GetPlatformTextureSettings("iPhone");
                settings.overridden = true;
                bool isPOT = IsPowerOfTwo(importer);
                if (IsAlphaTexture(importer))
                {
                    settings.format = isPOT ? TextureImporterFormat.PVRTC_RGBA4 : TextureImporterFormat.ASTC_4x4;
                }
                else
                {
                    settings.format = isPOT ? TextureImporterFormat.PVRTC_RGB4 : TextureImporterFormat.ASTC_6x6;
                }
                settings.compressionQuality = 100;
                importer.SetPlatformTextureSettings(settings);
            }
            else if (platform == BuildTarget.WebGL)
            {
                TextureImporterPlatformSettings settings = importer.GetPlatformTextureSettings("WebGL");
                settings.maxTextureSize = 1024;
#if ResizeOrginTexture
                if (!IsMultiOfFour(importer) || GetSize(importer) > settings.maxTextureSize)
#else
                if (!IsMultiOfFour(importer))
#endif
                {
                    ScaleToMO4(importer, settings.maxTextureSize);
                }
                settings.overridden = true;
                settings.allowsAlphaSplitting = false;
                //这里不考虑ETC_RGBA4Crunched的情况，因为某些非透明图即使是4的倍数也无法使用ETC_RGBA4Crunched
                settings.format = TextureImporterFormat.ETC2_RGBA8Crunched;
                settings.compressionQuality = 100;
                importer.SetPlatformTextureSettings(settings);
            }
        }

        private static void UnCompress(Object texture)
        {
            string path = AssetDatabase.GetAssetPath(texture);
            TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
            importer.mipmapEnabled = false;
            importer.npotScale = TextureImporterNPOTScale.None;

            //Android
            TextureImporterPlatformSettings settingsAndroid = importer.GetPlatformTextureSettings("Android");
            settingsAndroid.overridden = true;
            settingsAndroid.maxTextureSize = 4096;
            settingsAndroid.allowsAlphaSplitting = false;
            settingsAndroid.format = TextureImporterFormat.RGBA32;
            settingsAndroid.compressionQuality = 100;
            importer.SetPlatformTextureSettings(settingsAndroid);

            //iOS
            TextureImporterPlatformSettings settingsIOS = importer.GetPlatformTextureSettings("iPhone");
            settingsIOS.overridden = true;
            bool isPOT = IsPowerOfTwo(importer);
            settingsIOS.format = TextureImporterFormat.RGBA32;
            settingsIOS.compressionQuality = 100;
            importer.SetPlatformTextureSettings(settingsIOS);

            AssetDatabase.ImportAsset(path);
        }

        private static void StartDeleteMormalTexture(BuildTarget platform)
        {
            Object[] objs = Selection.GetFiltered(typeof(Texture2D), SelectionMode.DeepAssets);
            foreach (Object obj in objs)
            {
                Texture2D texture = obj as Texture2D;
                if (texture != null)
                {
                    string path = AssetDatabase.GetAssetPath(texture);
                    TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter;
                    if (importer != null && importer.textureType == TextureImporterType.NormalMap)
                    {
                        if (AssetDatabase.DeleteAsset(path))
                        {
                            Debug.Log($"删除 Normal Texture: {path}");
                        }
                    }
                }
            }
            AssetDatabase.Refresh();
        }

        //尺寸太大
        private static int GetSize(TextureImporter importer)
        {
            (int width, int height) = GetTextureImporterSize(importer);
            return width > height ? width : height;
        }

        //被4整除（Android用）
        private static bool IsMultiOfFour(TextureImporter importer)
        {
            (int width, int height) = GetTextureImporterSize(importer);
            return (width % 4 == 0 && height % 4 == 0);
        }

        //2的整数次幂（iOS用）
        private static bool IsPowerOfTwo(TextureImporter importer)
        {
            (int width, int height) = GetTextureImporterSize(importer);
            return (width == height) && (width > 0) && ((width & (width - 1)) == 0);
        }

        //带透明区域的图片
        private static bool IsAlphaTexture(TextureImporter importer)
        {
            return importer.DoesSourceTextureHaveAlpha();
        }

        //获取导入图片的宽高
        private static (int, int) GetTextureImporterSize(TextureImporter importer)
        {
            if (importer != null)
            {
                object[] args = new object[2];
                MethodInfo mi = typeof(TextureImporter).GetMethod("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance);
                mi.Invoke(importer, args);
                return ((int)args[0], (int)args[1]);
            }
            return (0, 0);
        }

        //把图片尺寸强制改成4的倍数
        private static void ScaleToMO4(TextureImporter importer, int maxSize)
        {
            if (importer != null)
            {
                object[] args = new object[2];
                MethodInfo mi = typeof(TextureImporter).GetMethod("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance);
                mi.Invoke(importer, args);
                int originW = (int)args[0];
                int originH = (int)args[1];
                if (originW > maxSize || originH > maxSize || originW % 4 != 0 || originH % 4 != 0)
                {
#if ResizeOrginTexture
                    if (originW > originH)
                    {
                        if (originW > maxSize)
                        {
                            float ratio = originH / (float)originW;
                            originW = maxSize;
                            originH = Mathf.RoundToInt(originW * ratio);
                        }
                    }
                    else
                    {
                        if (originH > maxSize)
                        {
                            float ratio = originW / (float)originH;
                            originH = maxSize;
                            originW = Mathf.RoundToInt(originH * ratio);
                        }
                    }
#endif

                    while (originW % 4 != 0)
                    {
                        originW -= 1;
                    }
                    while (originH % 4 != 0)
                    {
                        originH -= 1;
                    }

                    //还原为不压缩，才能正确读取tga图片原始数据
                    TextureImporterPlatformSettings settings = importer.GetPlatformTextureSettings("Android");
                    settings.overridden = false;
                    importer.SetPlatformTextureSettings(settings);
                    importer.isReadable = true;
                    importer.compressionQuality = 100;
                    importer.textureCompression = TextureImporterCompression.Uncompressed;
                    importer.SaveAndReimport();

                    string path = importer.assetPath;
                    Texture2D textureNew = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
                    textureNew = ScaleTexture(textureNew, originW, originH) as Texture2D;
                    if (textureNew)
                    {
                        if (path.EndsWith(".png"))
                        {
                            File.WriteAllBytes(path, textureNew.EncodeToPNG());
                        }
                        else if (path.EndsWith(".jpg"))
                        {
                            File.WriteAllBytes(path, textureNew.EncodeToJPG());
                        }
                        else if (path.EndsWith(".tga") || path.EndsWith(".tif"))
                        {
                            File.WriteAllBytes(path, textureNew.EncodeToTGA());
                        }
                        else if (path.EndsWith(".exr"))
                        {
                            File.WriteAllBytes(path, textureNew.EncodeToEXR());
                        }
                        importer.SaveAndReimport();
                    }
                }
            }
        }

        private static Texture ScaleTexture(Texture source, int targetWidth, int targetHeight)
        {
            Texture2D source2D = source as Texture2D;
            if (source2D != null)
            {
                Texture2D result = new Texture2D(targetWidth, targetHeight, source2D.format, false);
                for (int i = 0; i < result.height; ++i)
                {
                    for (int j = 0; j < result.width; ++j)
                    {
                        Color newColor = source2D.GetPixelBilinear((float)j / (float)result.width, (float)i / (float)result.height);
                        result.SetPixel(j, i, newColor);
                    }
                }
                result.Apply();
                return result;
            }
            return null;
        }
    }
}